/******************************************************************************
*
* Copyright (C) 2009 - 2014 Xilinx, Inc.  All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/

/*
 * helloworld.c: simple test application
 *
 * This application configures UART 16550 to baud rate 9600.
 * PS7 UART (Zynq) is not initialized by this application, since
 * bootrom/bsp configures it to baud rate 115200
 *
 * ------------------------------------------------
 * | UART TYPE   BAUD RATE                        |
 * ------------------------------------------------
 *   uartns550   9600
 *   uartlite    Configurable only in HW design
 *   ps7_uart    115200 (configured by bootrom/bsp)
 */

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xtop.h"
#include"xil_cache.h"
#include<stdlib.h>

#define N 4
#define M 8
#define Fsize 28
#define P 1
#define K 3
#define pool 0

short op(signed char x,int y){
	if(y==1)
		return (short)x;
	else
		return (short)-x;
}

void maxpool(short* in,short *out,int ch,int h,int w){
	for(int i=0;i<h/2;i++)
		for(int j=0;j<w/2;j++)
			for(int n=0;n<ch;n++){
				short max=-9999;
				for(int kx=0;kx<2;kx++)
					for(int ky=0;ky<2;ky++)
						if(*(in+n*h*w+(2*i+kx)*w+(2*j+ky))>max){
							max=*(in+n*h*w+(2*i+kx)*w+(2*j+ky));
						}
				*(out+n*h*w/4+i*w/2+j)=max;
			}
}

void conv(signed char *in,int *weight,short *out,int fsize,int pad,int ch_in,int ch_out){
    int fsize_o=fsize+2*pad-K+1;
    for(int m=0;m<ch_out;m++)
    	for(int r=0;r<fsize_o;r++)
    		for(int c=0;c<fsize_o;c++){
    			short tmp=0;
    			for(int i=0;i<K;i++)
    				for(int j=0;j<K;j++)
    					for(int n=0;n<ch_in;n++)
    						if(r+i-pad>=0&&r+i-pad<fsize&&c+j-pad>=0&&c+j-pad<fsize)
    							tmp+=op(in[n*fsize*fsize+(r+i-pad)*fsize+(c+j-pad)],
    									weight[m*ch_in*K*K+n*K*K+i*K+j]);
    			out[m*fsize_o*fsize_o+r*fsize_o+c]=tmp;
    	}
}

int main()
{
	printf("hello world\n");
    init_platform();
    XTop Hls_inst;
    const int weight[M][N][K][K]={
#include"weight.h"
    };
    signed char in[N][Fsize][Fsize];
    signed char in_copy[N][Fsize+2*P][Fsize+2*P];
    short out[M][Fsize][Fsize];
    short out_pool[M][Fsize/2][Fsize/2];
    short out_ref[M][Fsize][Fsize];
    short out_ref_pool[M][Fsize/2][Fsize/2];
    //
    for(int i=0;i<Fsize;i++)
    	for(int j=0;j<Fsize;j++)
    		for(int n=0;n<N;n++)
    			in[n][i][j]=(signed char)((n*Fsize*Fsize+i*Fsize+j)%255-127);
    for(int n=0;n<N;n++)
    	for(int i=0;i<Fsize+2*P;i++)
    		for(int j=0;j<Fsize+2*P;j++)
    			if(i>=P&&j>=P&&i<Fsize+P&&j<Fsize+P)
    				in_copy[n][i][j]=in[n][i-P][j-P];
    			else
    				in_copy[n][i][j]=(signed char)0;
    //conv((signed char*)in,(int*)weight,(short*)out_ref,Fsize,P,N,M);
    Xil_DCacheFlushRange((u32)in_copy,N*(Fsize+2)*(Fsize+2)*sizeof(signed char));

    //conv((signed char*)in,(int*)weight,(short*)out_ref,Fsize,P,N,M);

    if (XTop_Initialize(&Hls_inst, XPAR_TOP_0_DEVICE_ID) != XST_SUCCESS) {
    		printf("Initialize failed\n");
    		return -1;
    }
    XTop_Set_in1_V(&Hls_inst,(u32)in_copy);
    XTop_Set_in2_V(&Hls_inst,(u32)in_copy);
    if(pool==1)
    	XTop_Set_out_V(&Hls_inst,(u32)out_pool);
    else
    	XTop_Set_out_V(&Hls_inst,(u32)out);
    XTop_Set_fsize(&Hls_inst,(u32)(Fsize+2*P));
    XTop_Set_ch_in(&Hls_inst, (u32)(N));
    XTop_Set_ch_out(&Hls_inst,(u32)(M));
    XTop_Set_pool(&Hls_inst,(u32)pool);
    XTop_Start(&Hls_inst);
    //
    while (XTop_IsDone(&Hls_inst) == 0);
    if(pool==1)
    	Xil_DCacheInvalidateRange((u32)out_pool, M*Fsize*Fsize/4*sizeof(short));
    else
    	Xil_DCacheInvalidateRange((u32)out, M*Fsize*Fsize*sizeof(short));

    conv((signed char*)in,(int*)weight,(short*)out_ref,Fsize,P,N,M);//����λ���ƺ�Ӱ��IP�����н��
    maxpool((short*)out_ref,(short*)out_ref_pool,M,Fsize,Fsize);

    int error = 0;
    int correct = 0;
    if(pool==1){
    	for(int m=0;m<M;m++)
    		for (int i = 0; i < Fsize/2; i++)
    			for(int j = 0;j < Fsize/2;j++)
    			{
    				printf("%d,%d\n",out_pool[m][i][j],out_ref_pool[m][i][j]);
    				if(out_pool[m][i][j]==out_ref_pool[m][i][j])
    					correct++;
    				else
    					error++;
    			}
    }
    else{
    	for(int m=0;m<M;m++)
    	    for (int i = 0; i < Fsize; i++)
    	    	for(int j = 0;j < Fsize;j++)
    	    	{
    	    		printf("%d,%d\n",out[m][i][j],out_ref[m][i][j]);
    	    		if(out[m][i][j]==out_ref[m][i][j])
    	    			correct++;
    	    		else
    	    			error++;
    	    	}
    }
    printf("error=%d,correct=%d\n", error,correct);
    cleanup_platform();
    return 0;
}
